[Alexa日本語] プログレッシブレスポンスを使用して応答待ちの間に音楽やメッセージを流してユーザーを幸せにする
1 はじめに
外部のAPIをコールしているようなスキルでは、Alexaからのレスポンスが遅くなってしまうことがあります。青と緑のリングがグルグル回ってAlexaが頑張ってる(考えてる)感じのやつです。
少しの「待ち」であれば、これはこれで可愛いのですが・・・ちょっと長くなると、やはりUXは良くないかも知れません。
通常のスキルの実装は、下記のような順で処理されます。
① リクエストを受ける ② 内部処理(外部APIコールなど) ③ レスポンスを返す
このため、ユーザーの発話に対してAlexaが返事を始めるのは、③のレスポンスを受けてからですので、②が長くなると返事が遅くなるのは避けようがありません。
今回は、②の前に一旦Alexaから何らかの返事(発話や音楽など)を返しておき、②が終わった時点で、改めてレスポンスを返すという実装を試してみたいと思います。
① リクエストを受ける レスポンスを返す (Progressive Response) 「現在、検索中です。少しお待ちください ♪♪♫♪♬」 ② 内部処理(外部APIコールなど) ③ レスポンスを返す
2 プログレッシブレスポンス(Progressive Response)
Progressive Responseは、スキルの応答を待っている間にAlexaが再生するコンテンツであり、SSMLが使用可能なため、テキストや短いオーディオを利用することが可能です。スキルがリクエストを受け取り、現在、処理中であることを返すことができるため、ユーザーは「待ち」に入っていることが認識でき、安心感を得ることが出来ます。
Progressive Responseは、LaunchRequestまたは、IntentRequestから使用できます。
Progressive Responseは、リクエストに含まれるapiAccessToken及び、requestIdを使用してVoicePlayer.SpeakなどをPOSTすることで送ることできます。通常のレスポンスオブジェクトを受信する前に、これが到着した場合、デバイスで再生されます。
Directive Request
POST https://api.amazonalexa.com/v1/directives HTTP/1.1 Authorization: Bearer AxThk... Content-Type: application/json { "header":{ "requestId":"amzn1.echo-api.request.xxxxxxx" }, "directive":{ "type":"VoicePlayer.Speak", "speech":"This text is spoken while your skill processes the full response." } }
なお、Progressive Responseを使用しても、レスポンスの制限時間(8秒以内)を超えることは出来ませんので注意して下さい。
3 SDKによる実装
Progressive Responseは、現在、Alexa SDK for Nodejsで記述が可能です。
最初に、比較のため時間のかかる処理を書いてみました。単純に7秒のウエイトを入れただけのコードです。
'SearchIntent': function () { // 通常の処理 let that = this; let query = this.event.request.intent.slots.query.value; setTimeout(function(){ that.emit(':ask', query + 'を検索しました。他にも何か検索しますか'); },7000); },
続いて、上記の処理にProgressive Responseを追加したものです。通常の処理とProgressive Response用の処理をPromiseオブジェクトとして用意し、Promise.all()で実行しています。
Promise.all()では、複数の処理が全部終わってからthenに進むので、Progressive Response用の処理は、実処理側の所要時間を考慮して作成するべきでしょう。
今回は、発話と音楽でだいたい7秒程度の処理を用意しました。
'MusicSearchIntent': function () { // プログレッシブレスポンスを返す処理 let that = this; let query = this.event.request.intent.slots.query.value; const requestId = this.event.request.requestId; const token = this.event.context.System.apiAccessToken; const endpoint = this.event.context.System.apiEndpoint; const ds = new Alexa.services.DirectiveService(); const audio = 'https://s3-ap-northeast-1.amazonaws.com/devio-blog-data/output.mp3'; const ssml = '<speak>検索を開始します<audio src="' + audio + '" /></speak>'; const directive = new Alexa.directives.VoicePlayerSpeakDirective(requestId, ssml); const progressiveResponse = ds.enqueue(directive, endpoint, token) .catch((err) => { console.log(err); }); const serviceCall = new Promise((resolve, reject) => { setTimeout( () => { resolve(query); },7000); }) Promise.all([progressiveResponse, serviceCall]) .then( query => { that.emit(':ask', '音楽付きで検索しました。他にも何か検索しますか'); }); }
それでは、動作している様子です。一回目の呼出は、通常の処理で、二回目は、プログレッシブレスポンスの入った処理です。
4 最後に
今回は、プログレッシブレスポンスを使用して、応答待ち時間に音楽やメッセージを再生してみました。ユーザーの体験を向上させる手法としては、非常に有効な手法だと思います。うまく組み合わせて積極的に使用して行きたいと思います。